package com.twj.tools.poi;


import com.twj.tools.parse.CastUtils;
import com.twj.tools.parse.JsonUtils;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.twj.tools.img.ImageUtil.convertBase64StrToImage;

/**
 * @author 作者: tianwenju
 * @version 1.0
 * @project 金税三期工程核心征管及应用总集成项目
 * @package
 * @file DataDownload.java 创建时间:2023年07月04日 16:03
 * @title 生成word
 * @description https://poi.apache.org/index.html
 * @copyright Copyright (c) 2020 中国软件与技术服务股份有限公司
 * @company 中国软件与技术服务股份有限公司
 * @module 生成word工具类
 * @reviewer 审核人:
 * @history 修订历史（历次修订内容、修订人、修订时间等）
 */
public class WordCreateUtil {

    /**
     * word整体样式
     */
    private static CTStyles wordStyles = null;

    private static int TITLE_SIZE = 16;
    private static int HEAD_SIZE = 14;
    private static int TEXT_SIZE = 12;

    /**
     * Word整体样式
     */
    static {
        XWPFDocument template;
        try {
            // 读取模板文档
//            final HttpServletRequest request = ContextAPI.getReq();
//            final String filepath = request.getSession().getServletContext().getRealPath("/yqssdsj/download" + File.separator + "template.docx");
//            template = new XWPFDocument(new FileInputStream(filepath));
            template = new XWPFDocument(new FileInputStream("D:\\test\\template.docx"));
            // 获得模板文档的整体样式
            wordStyles = template.getStyle();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XmlException e) {
            e.printStackTrace();
        }
    }

    private static void test() throws FileNotFoundException {
        XWPFDocument doc = new XWPFDocument();

        CTDocument1 document = doc.getDocument();
        CTBody body = document.getBody();
        if (!body.isSetSectPr()) {
            body.addNewSectPr();
        }
        CTSectPr section = body.getSectPr();

        if (!section.isSetPgSz()) {
            section.addNewPgSz();
        }
        CTPageSz pageSize = section.getPgSz();
        pageSize.setW(BigInteger.valueOf(16840));
        pageSize.setH(BigInteger.valueOf(11905));
        pageSize.setOrient(STPageOrientation.LANDSCAPE);


        //添加标题
        XWPFParagraph titleParagraph = doc.createParagraph();

        //设置段落居中
        titleParagraph.setAlignment(ParagraphAlignment.CENTER);

        XWPFRun titleParagraphRun = titleParagraph.createRun();
        titleParagraphRun.setText("机  车  轮  对  检  修  记  录");
        titleParagraphRun.setColor("000000");
        titleParagraphRun.setFontSize(20);
        titleParagraphRun.setBold(true);
        //添加第一行正文
        XWPFParagraph textParagraph = doc.createParagraph();

        textParagraph.setAlignment(ParagraphAlignment.LEFT);

        XWPFRun textParagraphRun = textParagraph.createRun();
        String engineTypeName = "AA";
        String axleNo = "90";
        textParagraphRun.setText("机型：  " + engineTypeName + "                     轴号：  " + axleNo + "          编号：");
        textParagraphRun.setColor("000000");
        textParagraphRun.setFontSize(9);

        //表格
        XWPFTable table = doc.createTable(13, 19);
        int[] colWidths = {1400, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650, 650};
        //设置指定宽度
        CTTbl ttbl = table.getCTTbl();
        CTTblGrid tblGrid = ttbl.addNewTblGrid();
        for (int i : colWidths) {
            CTTblGridCol gridCol = tblGrid.addNewGridCol();
            gridCol.setW(new BigInteger(i + ""));
        }
        List<XWPFTableRow> rows = table.getRows();
        for (XWPFTableRow row : rows) {
            CTTrPr trPr = row.getCtRow().addNewTrPr();
            CTHeight ht = trPr.addNewTrHeight();
            ht.setVal(BigInteger.valueOf(600));
        }

        mergeCellsHorizontal(table, 2, 17, 18);
        mergeCellsVertically(table, 15, 1, 2);
        //填值
        List<XWPFTableRow> rowList = table.getRows();
        for (int i = 0; i < rowList.size(); i++) {
            XWPFTableRow infoTableRow = rowList.get(i);
            List<XWPFTableCell> cellList = infoTableRow.getTableCells();
            for (int j = 0; j < cellList.size(); j++) {
                cellList.get(j).setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
                XWPFParagraph cellParagraph = cellList.get(j).getParagraphs().get(0);
                cellParagraph.setAlignment(ParagraphAlignment.CENTER);
                XWPFRun cellParagraphRun = cellParagraph.createRun();
                cellParagraphRun.setFontSize(10);
                if (i == 0) {
                    if (j == 0) {
                        cellParagraphRun.setText("原装车");
                    }
                }
                cellParagraphRun.setText("hhd");
                cellParagraphRun.setFontSize(12);
                cellParagraphRun.setBold(true);
                cellParagraphRun.setShadow(true);
            }
        }

        try {
            doc.write(new FileOutputStream("D:\\test\\66.docx"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                doc.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * @param table    表
     * @param row      行号
     * @param fromCell 起
     * @param toCell   止
     * @description 水平列合并
     * @time 创建时间：2023/7/13 15:06
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) {

        for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {
            XWPFTableCell cell = table.getRow(row).getCell(cellIndex);
            if (cellIndex == fromCell) {
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
            } else {
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
            }
        }
    }

    /**
     * @param table   表
     * @param col     列号
     * @param fromRow 起
     * @param toRow   止
     * @description 行合并
     * @time 创建时间：2023/7/13 15:08
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {

        for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
            XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
            if (rowIndex == fromRow) {
                cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
            } else {
                cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
            }
        }
    }

    /**
     * @param paramMap 内容参数
     * @return doc
     * @description 根据参数内容，生成word
     * @time 创建时间：2023/7/6 14:46
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static XWPFDocument generateWordDoc(Map<String, Object> paramMap) {
        String content = "{\"ztbm\":\"0000000001\",\"xxxx\":{\"xxmc\":\"现象一：【X%】的【维度/标签】贡献了【Y%】的【指标】\",\"xxms\":\"全国【YYYY】年【X%】【维度/标签】贡献了【Y%】【指标】，主要集中在【省份】、【行业】，呈现了一定的聚集性。\"},\"gxxx\":{\"xxwj\":\"【XXX省】  【姓名】（【XXX】税务局）\",\"sjsh\":\"国家税务总局 【姓名】\",\"bj\":\"【XXX省】  【姓名】（【XXX】税务局）\"},\"zsxx\":{\"sjwjgc\":\"关联计算一【人/员/户/局/票】式归集的【XXXX信息】【XXXX万/亿条】，【YYYY-4】-【YYYY】年【XXXX信息】【XXXX万/亿条】\",\"zyzbbq\":\"【指标名称】、【指标名称】\"},\"xxnr\":[{\"nrbt\":\"内容1\",\"tbxx\":\"\",\"nrxx\":\"1.【YYYY】年，全国【指标】合计值为【XXX】【单位】，其中【X%】的【维度/标签】贡献了【指标】合计值为【XXX】【单位】，占全国【指标】合计值【百分比%】，【指标】贡献排名前三的省份分别为【XX省】、【XX省】和【XX省】，分别占全国总量的【百分比%】、【百分比%】和【百分比%】，（详见表X.1）。\"},{\"nrbt\":\"内容2\",\"tbxx\":\"\",\"nrxx\":\"【YYYY】年，全国【指标】行业集中情况，【指标】排名前三的行业分别为【XX行业】、【XX行业】和【XX行业】，分别占全国总量的【百分比%】、【百分比%】和【百分比%】\"}],\"fjbbdm\":[\"100302\",\"100301\",\"100304\",\"100303\"]}";

        paramMap = JsonUtils.str2Map(content);
        //1.构建文档对象
        XWPFDocument doc = new XWPFDocument();
        // doc.createStyles().setStyles(wordStyles);

        //主题编码
        String ztbm = (String) paramMap.get("ztbm");
        //现象信息
        Map<String, String> xxxx = (Map<String, String>) paramMap.get("xxxx");
        //内容信息
        List<Map<String, String>> xxnr = (List<Map<String, String>>) paramMap.get("xxnr");
        //贡献信息
        Map<String, String> gxxx = (Map<String, String>) paramMap.get("gxxx");
        //注释信息
        Map<String, String> zsxx = (Map<String, String>) paramMap.get("zsxx");
        //附件信息
        List<String> fjxx = (List<String>) paramMap.get("fjbbdm");


//        final String ztmc = GyUtils.getMcByDm("DM_SJFXBG_BGZTB", ztbm, "ZTLXMC");
//        Map<String, Object> ztMap = SjfxbgGyUtils.getZtdescCacheData(ztbm);
//        final String zttitle = (String) ztMap.get("zttitle");
//        final String ztms = (String) ztMap.get("ztdesc");

        createTitle(doc, "主题名称", TITLE_SIZE);
        createTitle(doc, "副标题", HEAD_SIZE);
        createParagraph(doc, "描述。。。。。。。。。。。。。。。。。。");


        // 段落
        createChapter(doc, "4", xxxx.get("xxmc"), HEAD_SIZE);
        createParagraph(doc, xxxx.get("xxms"));

        for (Map<String, String> map : xxnr) {
            String nrbt = map.get("nrbt");
            String nrxx = map.get("nrxx");
            String tbxx = map.get("tbxx");
            createChapter(doc, "4", nrbt, HEAD_SIZE);
            createParagraph(doc, nrxx);
            if (!StringUtils.isEmpty(tbxx)) {
                String[] base64Info = tbxx.split(",");
                String info = base64Info[0];
                String suffix = info.substring(info.indexOf('/') + 1, info.indexOf(';'));
                File file = convertBase64StrToImage(base64Info[1], "tbxx-word." + suffix);
                addPicture(doc, file, suffix);
                if (file.exists()) {
                    file.delete();
                }
            }
        }

        createChapter(doc, "4", "主要贡献和个人", HEAD_SIZE);
        createParagraph(doc, "现象挖掘：" + gxxx.get("xxwj"));
        createParagraph(doc, "数据审核：" + gxxx.get("sjsh"));
        createParagraph(doc, "编辑：" + gxxx.get("bj"));

        createChapter(doc, "4", "注释", HEAD_SIZE);
        createParagraph(doc, "1.数据挖掘过程");
        createParagraph(doc, zsxx.get("sjwjgc"));
        createParagraph(doc, "2.主要指标标签");
        createParagraph(doc, zsxx.get("zyzbbq"));

        createChapter(doc, "4", "附件", HEAD_SIZE);
        if (!CollectionUtils.isEmpty(fjxx)) {
            for (String bbdm : fjxx) {
                createAttachment(doc, bbdm);
            }
        }
        return doc;
    }

    /**
     * @param doc
     * @param text     文本
     * @param fontSize 字号
     * @return 报表数据
     * @description 通过报表代码获取报表数据(行数据 ， 列数据 ， 表头)
     * @time 创建时间：2023/7/11 14:36
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    private static void createTitle(XWPFDocument doc, String text, int fontSize) {
        // 标题
        XWPFParagraph para = doc.createParagraph();
        //para.setStyle("4");//一级标题
        para.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun xwpfRun = para.createRun();
        xwpfRun.setBold(true);
        xwpfRun.setFontFamily("宋体");
        xwpfRun.setText(text);
        xwpfRun.setFontSize(fontSize);
    }

    /**
     * @param bbdm 报表代码
     * @return 报表数据
     * @description 通过报表代码获取报表数据(行数据 ， 列数据 ， 表头)
     * @time 创建时间：2023/7/11 14:36
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    private static Map<String, Object> queryTableDataByBbdm(String bbdm) {
        // 查询数据
//        Map<String, Object> dataMap = (Map<String, Object>) SwordServiceUtils.callService("DSJYPT.QJSKJSY.HDXT.GY.QUERYCOMPONENTSC.GETRECORDLIST", new HashMap<>(), bbdm);
        List<Map<String, Object>> rowList;
//        rowList = (List<Map<String, Object>>) dataMap.get("data");
        // 查询配置表头信息
        final List<Map<String, Object>> colList;
//        colList = (List<Map<String, Object>>) SwordServiceUtils.callService("DSJYPT.QJSKJSY.HDXT.GY.QUERYCOMPONENTSC.QUERYCOLBYBBDM", bbdm);

        String rows = "[{\"tjnd\":\"2023\",\"bhlb\":\"01\",\"qxzsl\":1233,\"qxsl\":1023,\"zbmc\":\"入库税额\"},{\"tjnd\":\"2023\",\"bhlb\":\"01\",\"qxzsl\":435,\"qxsl\":43,\"zbmc\":\"入库税额\"},{\"tjnd\":\"2023\",\"bhlb\":\"02\",\"qxzsl\":543,\"qxsl\":342,\"zbmc\":\"入库税额\"},{\"tjnd\":\"2023\",\"bhlb\":\"01\",\"qxzsl\":875,\"qxsl\":543,\"zbmc\":\"入库税额\"},{\"tjnd\":\"2023\",\"bhlb\":\"01\",\"qxzsl\":876,\"qxsl\":645,\"zbmc\":\"入库税额\"},{\"tjnd\":\"2023\",\"bhlb\":\"01\",\"qxzsl\":865,\"qxsl\":76,\"zbmc\":\"入库税额\"},{\"tjnd\":\"2023\",\"bhlb\":\"01\",\"qxzsl\":765,\"qxsl\":645,\"zbmc\":\"入库税额\"},{\"tjnd\":\"2023\",\"bhlb\":\"01\",\"qxzsl\":765,\"qxsl\":76,\"zbmc\":\"入库税额\"},{\"tjnd\":\"2023\",\"bhlb\":\"01\",\"qxzsl\":645,\"qxsl\":42,\"zbmc\":\"入库税额\"},{\"tjnd\":\"2023\",\"bhlb\":\"01\",\"qxzsl\":423,\"qxsl\":76,\"zbmc\":\"入库税额\"},{\"tjnd\":\"2023\",\"bhlb\":\"01\",\"qxzsl\":876,\"qxsl\":86,\"zbmc\":\"入库税额\"},{\"tjnd\":\"2023\",\"bhlb\":\"01\",\"qxzsl\":1233,\"qxsl\":2345,\"zbmc\":\"【2023】年全国【88.27%】的县区【纳税人数量】同比【增长】\"},{\"tjnd\":\"2022\",\"bhlb\":\"02\",\"qxzsl\":34543,\"qxsl\":5676,\"zbmc\":\"【2023】年全国【34.27%】的县区【纳税人数量】同比【减少】\"}]";
        String cols = "[{\"colend\":1,\"bbDm\":\"100302\",\"sort\":\"\",\"align\":\"center\",\"columnname\":\"djxh\",\"colbegin\":1,\"rowbegin\":1,\"columncommnet\":\"序号\",\"autoincrement\":\"\",\"drilltype\":\"\",\"width\":\"16%\",\"drillurl\":\"\",\"fixed\":\"\",\"id\":4010,\"rowend\":1},{\"colend\":2,\"bbDm\":\"100302\",\"sort\":\"\",\"align\":\"center\",\"columnname\":\"bhlb\",\"colbegin\":2,\"rowbegin\":1,\"columncommnet\":\"变化类别\",\"autoincrement\":\"\",\"drilltype\":\"\",\"width\":\"16%\",\"drillurl\":\"\",\"fixed\":\"\",\"id\":4011,\"rowend\":1},{\"colend\":3,\"bbDm\":\"100302\",\"sort\":\"\",\"align\":\"center\",\"columnname\":\"qxsl\",\"colbegin\":3,\"rowbegin\":1,\"columncommnet\":\"区县数量\",\"autoincrement\":\"\",\"drilltype\":\"\",\"width\":\"16%\",\"drillurl\":\"\",\"fixed\":\"\",\"id\":4012,\"rowend\":1},{\"colend\":4,\"bbDm\":\"100302\",\"sort\":\"\",\"align\":\"center\",\"columnname\":\"qxzsl\",\"colbegin\":4,\"rowbegin\":1,\"columncommnet\":\"区县总数量\",\"autoincrement\":\"\",\"drilltype\":\"\",\"width\":\"16%\",\"drillurl\":\"\",\"fixed\":\"\",\"id\":4013,\"rowend\":1},{\"colend\":5,\"bbDm\":\"100302\",\"sort\":\"\",\"align\":\"center\",\"columnname\":\"zbmc\",\"colbegin\":5,\"rowbegin\":1,\"columncommnet\":\"指标名称\",\"autoincrement\":\"\",\"drilltype\":\"\",\"width\":\"17%\",\"drillurl\":\"\",\"fixed\":\"\",\"id\":4014,\"rowend\":1},{\"colend\":6,\"bbDm\":\"100302\",\"sort\":\"\",\"align\":\"center\",\"columnname\":\"tjnd\",\"colbegin\":6,\"rowbegin\":1,\"columncommnet\":\"统计年度\",\"autoincrement\":\"\",\"drilltype\":\"\",\"width\":\"17%\",\"drillurl\":\"\",\"fixed\":\"\",\"id\":4015,\"rowend\":1}]";
        rowList = JsonUtils.str2List(rows);
        colList = JsonUtils.str2List(cols);
        String title = "表名称1";
        Map<String, Object> res = new HashMap<>();
        res.put("title", title);
        res.put("rows", rowList);
        res.put("cols", colList);
        return res;
    }

    /**
     * @param bbdm 报表代码
     * @return
     * @description 创建附件
     * @time 创建时间：2023/7/11 14:36
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    private static void createAttachment(XWPFDocument doc, String bbdm) {

        Map<String, Object> tableData = queryTableDataByBbdm(bbdm);
        List<Map<String, Object>> rows = (List<Map<String, Object>>) tableData.get("rows");
        List<Map<String, Object>> cols = (List<Map<String, Object>>) tableData.get("cols");
        if (CollectionUtils.isEmpty(rows) || CollectionUtils.isEmpty(cols)) {
            return;
        }
        String title = (String) tableData.get("title");
        createParagraph(doc, title, ParagraphAlignment.CENTER);
        createTable(doc, rows, cols);

    }

    /**
     * @param doc
     * @param file   图片
     * @param suffix 文件后缀
     * @description 添加圖片，文字环绕型
     * @time 创建时间：2023/7/4 15:04
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    private static void addPicture(XWPFDocument doc, File file, String suffix) {

        XWPFRun run = doc.createParagraph().createRun();
        InputStream in;
        //计算适合文档宽高的图片EMU数值
        BufferedImage read = null;
        int picWidth, picHeight;
        try {
            read = ImageIO.read(file);
            int width = read.getWidth();
            int height = read.getHeight();
            //下面按照图片的实际大小进行同比例缩放
            picWidth = 400;
            picHeight = picWidth * height / width;

            in = new FileInputStream(file);
            run.addPicture(in, getPictureType(suffix), file.getName(), Units.toEMU(picWidth), Units.toEMU(picHeight));
            in.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // 2. 获取到图片数据
        CTDrawing drawing = run.getCTR().getDrawingArray(0);
        CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic();
        //拿到新插入的图片替换添加CTAnchor 设置浮动属性 删除inline属性
        CTAnchor anchor = getAnchorWithGraphic(graphicalobject, "TEST1", Units.toEMU(picWidth), Units.toEMU(picHeight),//图片大小
                Units.toEMU(10), Units.toEMU(0), false);//相对当前段落位置 需要计算段落已有内容的左偏移
        drawing.setAnchorArray(new CTAnchor[]{anchor});//添加浮动属性
        drawing.removeInline(0);//删除行内属性
        addPicHolderParagraph(doc, picHeight);
    }

    private static int getPictureType(String picType) {
        int res = XWPFDocument.PICTURE_TYPE_PICT;
        if (picType != null) {
            if (picType.equalsIgnoreCase("png")) {
                res = XWPFDocument.PICTURE_TYPE_PNG;
            } else if (picType.equalsIgnoreCase("dib")) {
                res = XWPFDocument.PICTURE_TYPE_DIB;
            } else if (picType.equalsIgnoreCase("emf")) {
                res = XWPFDocument.PICTURE_TYPE_EMF;
            } else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) {
                res = XWPFDocument.PICTURE_TYPE_JPEG;
            } else if (picType.equalsIgnoreCase("wmf")) {
                res = XWPFDocument.PICTURE_TYPE_WMF;
            }
        }
        return res;
    }

    /**
     * @param doc
     * @param height 高度
     * @description 添加图片占位段落，否则图片会叠加
     * @time 创建时间：2023/7/4 15:00
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    private static void addPicHolderParagraph(XWPFDocument doc, int height) {

        int count = height / TITLE_SIZE;
        for (int i = 0; i <= count; i++) {
            doc.createParagraph();
        }
    }

    /**
     * @param ctGraphicalObject 图片数据
     * @param deskFileName      图片描述
     * @param width             宽
     * @param height            高
     * @param leftOffset        水平偏移 left
     * @param topOffset         垂直偏移 top
     * @param behind            文字上方，文字下方
     * @return
     * @description 图片xml 文字环绕型非内嵌
     * @time 创建时间：2023/7/4 14:58
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static CTAnchor getAnchorWithGraphic(CTGraphicalObject ctGraphicalObject, String deskFileName, int width, int height, int leftOffset, int topOffset, boolean behind) {

        String anchorXML = "<wp:anchor xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" " + "simplePos=\"0\" relativeHeight=\"0\" behindDoc=\"" + ((behind) ? 1 : 0) + "\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">" + "<wp:simplePos x=\"0\" y=\"0\"/>" + "<wp:positionH relativeFrom=\"column\">" + "<wp:posOffset>" + leftOffset + "</wp:posOffset>" + "</wp:positionH>" + "<wp:positionV relativeFrom=\"paragraph\">" + "<wp:posOffset>" + topOffset + "</wp:posOffset>" + "</wp:positionV>" + "<wp:extent cx=\"" + width + "\" cy=\"" + height + "\"/>" + "<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>" + "<wp:wrapNone/>" + "<wp:docPr id=\"1\" name=\"Drawing 0\" descr=\"" + deskFileName + "\"/><wp:cNvGraphicFramePr/>" + "</wp:anchor>";

        CTDrawing drawing = null;
        try {
            drawing = CTDrawing.Factory.parse(anchorXML);
        } catch (XmlException e) {
            e.printStackTrace();
        }
        CTAnchor anchor = drawing.getAnchorArray(0);
        anchor.setGraphic(ctGraphicalObject);
        return anchor;
    }


    /**
     * @param doc     文档
     * @param rowList 行数据
     * @param colList 列数据 表头
     * @return
     * @description 生成大表哥
     * @time 创建时间：2023/7/4 14:58
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    private static void createTable(XWPFDocument doc, List<Map<String, Object>> rowList, List<Map<String, Object>> colList) {
        // 表格
        XWPFTable table = doc.createTable(rowList.size() + 1, colList.size());
        //设置指定宽度
        setTableStyle();
        //设置标题
        Map<Integer, String> titleMap = new HashMap<>();

        for (int i = 0; i < colList.size(); i++) {
            titleMap.put(CastUtils.cast2Int(colList.get(i).get("colbegin")), CastUtils.cast2Str(colList.get(i).get("columnname")));
        }
        XWPFTableRow firstRow = table.getRows().get(0);
        List<XWPFTableCell> tableCells = firstRow.getTableCells();
        for (int i = 0; i < tableCells.size(); i++) {
            tableCells.get(i).setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
            XWPFParagraph cellParagraph = tableCells.get(i).getParagraphs().get(0);
            cellParagraph.setAlignment(ParagraphAlignment.CENTER);
            XWPFRun cellParagraphRun = cellParagraph.createRun();
//
            String colName = CastUtils.cast2Str(colList.get(i).get("columncommnet"));
            cellParagraphRun.setText(colName);
            cellParagraphRun.setBold(true);
            cellParagraphRun.setFontSize(10);
        }
        //合并操作。。
        //填值
        List<XWPFTableRow> rows = table.getRows();
        for (int i = 1, row = 0; i < rows.size(); i++, row++) {
            XWPFTableRow infoTableRow = rows.get(i);
            List<XWPFTableCell> cells = infoTableRow.getTableCells();
            Map<String, Object> rowMap = rowList.get(row);

            for (int j = 0, col = 1; j < cells.size(); j++, col++) {
                cells.get(j).setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
                XWPFParagraph cellParagraph = cells.get(j).getParagraphs().get(0);
                cellParagraph.setAlignment(ParagraphAlignment.CENTER);
                cellParagraph.setVerticalAlignment(TextAlignment.CENTER);
                XWPFRun cellParagraphRun = cellParagraph.createRun();
//                cellParagraphRun.setFontSize(10);
                String text = CastUtils.cast2Str(rowMap.get(titleMap.get(col)));
                cellParagraphRun.setText(text);
            }
        }


    }

    private static void setTableStyle() {
//        1.表格或单元格宽度：
//
//默认TblW的type属性为STTblWidth.AUTO,即自动伸缩。所以要调整为指定类型：STTblWidth.DXA 1）表格宽：
//
//CTTblPr tblPr = xtab2.getCTTbl().getTblPr();
//
//tblPr.getTblW().setType(STTblWidth.DXA);
//
//tblPr.getTblW().setW(new BigInteger("7000"));
//
//单元格宽：
//
//CTTcPr tcpr = cell.getCTTc().addNewTcPr();
//
//CTTblWidth cellw = tcpr.addNewTcW();
//
//cellw.setType(STTblWidth.DXA);
//
//cellw.setW(BigInteger.valueOf(360*5));
//
//2.表格风格
//
//注：如果不设置风格，将采用默认的Normal风格
//
//CTTblPr tblPr = xtab2.getCTTbl().getTblPr();
//
//CTString styleStr = tblPr.addNewTblStyle();
//
//styleStr.setVal("StyledTable");
//
//3.表格行高：获取表格行的CTTrPr.增加CTHeight属性
//
//List rows = xtab2.getRows();
//
//for (XWPFTableRow row : rows) {
//
//CTTrPr trPr = row.getCtRow().addNewTrPr();
//
//CTHeight ht = trPr.addNewTrHeight();
//
//ht.setVal(BigInteger.valueOf(360));
    }

    /**
     * @param doc
     * @param style    样式
     * @param content  内容
     * @param fontSize 字体大小
     * @description 添加章节
     * @time 创建时间：2023/7/4 15:02
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static void createChapter(XWPFDocument doc, String style, String content, Integer fontSize) {

        XWPFParagraph paragraph = doc.createParagraph();
//        paragraph.setStyle(style);//一级标题

        //设置位置 居中 左 右
        paragraph.setAlignment(ParagraphAlignment.LEFT);
        XWPFRun xwpfRun = paragraph.createRun();
        xwpfRun.setBold(true);
        xwpfRun.setText(content);
        xwpfRun.setFontSize(fontSize);
        //xwpfRun.setFontFamily("楷体_GB2312");
    }


    /**
     * @param doc
     * @param content 内容
     * @description 添加段落
     * @time 创建时间：2023/7/4 15:02
     * @author 作者：tianwenju
     * @history 修订历史（历次修订内容、修订人、修订时间等）
     */
    public static void createParagraph(XWPFDocument doc, String content) {
        createParagraph(doc, content, ParagraphAlignment.LEFT);
    }

    public static void createParagraph(XWPFDocument doc, String content, ParagraphAlignment align) {
        XWPFParagraph paragraph = doc.createParagraph();
        paragraph.setAlignment(align);

        paragraph.setIndentationLeft(12); //设置左缩进
        paragraph.setIndentationRight(12); //设置右缩进
        paragraph.setFirstLineIndent(24); //设置首行缩进
        //paragraph.setLeading(50f); //行间距
        paragraph.setSpacingBefore(5); //设置段落上空白
        paragraph.setSpacingAfter(10); //设置段落下空白

        XWPFRun xwpfRun = paragraph.createRun();
        xwpfRun.setText(content);
        xwpfRun.setFontSize(TEXT_SIZE);

    }

    public static void main(String[] args) throws Exception {

        XWPFDocument xwpfDocument = generateWordDoc(new HashMap<>());
        xwpfDocument.write(new FileOutputStream("D:\\test\\99.docx"));
        // formatDoc();
//        test();
        System.out.println("word  finish!!");
    }
}